<!-- eslint-disable vue/no-mutating-props -->
<template>
  <div id="app-container">
    <el-container v-loading="renderDiagramLoading" style="min-height: 700px ;width:100% ;">
       <el-tabs v-model="activeName" type="border-card" style="width:100%" @tab-click="handleClick">
        <el-tab-pane label="流程设计" name="first">
          <div id="processDesign" ref="processDesign" class="processDesign">
            <el-header style="height: auto;padding: 0px;">
              <!-- 头部 -->
              <ukulele-bpmn-header v-if="bpmnModeler" id="designHeader" ref="designHeader" class="designHeader"
                :bpmn-modeler.sync="bpmnModeler" :process-info.sync="processInfo" @save='saveBpmn'/>
            </el-header>
            <div class="centerClass">
              <el-container>
                <el-main v-loading="renderDiagramLoading">
                  <div ref="content" class="containers" style='margin: -20px;'>
                    <div ref="canvas" class="canvas"/>
                  </div>
                </el-main>
                <el-aside width="20%" style='height:850px'>
                  <ukulele-bpmn-right v-if="bpmnModeler" id="designRight" ref="designRight"
                    :process-info.sync="processInfo" :bpmn-modeler.sync="bpmnModeler" class="designRight"
                    @getNodeAction='getNodeAction' @getAreaAction="getAreaAction" @getDepartmentAction="getDepartmentAction"
                    @getRoleAction="getRoleAction" @getRuleAction="getRuleAction"/>
                </el-aside>
              </el-container>
            </div>
          </div>
        </el-tab-pane>
        <!-- <el-tab-pane label="流程设置" name="five">
        </el-tab-pane>
        <el-tab-pane label="流程规则" name="second">
        </el-tab-pane> -->
        <!-- <el-tab-pane label="变量管理" name="third">
          <fx-variable-list v-if="showVarDict" ref="varDict"
            :process-info.sync="processInfo" :bpmn-modeler.sync="bpmnModeler" :process-key.sync="processInfo.processKey"/>
        </el-tab-pane> -->
        <el-tab-pane label="BPMNXML" name="fourth">
          <bpmn-xml v-if="showBpmn" ref="bpmnXml" :process-diagram-xml.sync="processDiagramXml" />
        </el-tab-pane>
      </el-tabs>
    </el-container>
  </div>
</template>
<script>
import ukuleleBpmnHeader from './component/header.vue'
import customTranslate from './component/i18n-bpmn/customTranslate'
import BpmnModeler from './component/modeler'
import customControlsModule from './component/modeler/custom'
import ukuleleBpmnRight from './component/right.vue'
// import fxVariableList from './component/variable/variableList'
// import minimapModule from './component/minimap'
import minimapModule from 'diagram-js-minimap'
// 校验
import transactionBoundariesModule from 'camunda-transaction-boundaries'
import lintModule from 'bpmn-js-bpmnlint'
import bpmnlintConfig from '../.bpmnlintrc'

import tokenSimulation from 'bpmn-js-token-simulation/lib/viewer'

import BpmnXml from './component/bpmnxml.vue'
import { defaultDiagramXML } from './resources/diagram/exampleDiagram'
import activitiModdleDescriptor from './component/js/activiti.json'
import Ids from 'ids'

export default {
  name: 'ukulele-bpmn-modeler',
  components: { ukuleleBpmnHeader, ukuleleBpmnRight, BpmnXml },
  props: {
    newProcessDiagramXml: {
      type: String,
      required: true,
      default: null
    },
    processInfo: {
      type: Object,
      require: true,
      default: null
    },
    loading: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      screenHeight: 800,
      bpmnModeler: null,
      container: null,
      canvas: null,
      processDiagramXml: '',
      renderDiagramLoading: true,
      activeName: 'first',
      showVarDict: false,
      showBpmn: true
    }
  },
  computed: {

  },
  mounted() {
    this.screenHeight = document.body.clientHeight - 5
    // 获取到属性ref为“content”的dom节点
    this.container = this.$refs.content
    // 获取到属性ref为“canvas”的dom节点
    const canvas = this.$refs.canvas
    const customTranslateModule = {
      translate: ['value', customTranslate]
    }
    // 建模，官方文档这里讲的很详细
    this.bpmnModeler = new BpmnModeler({
      container: canvas,
      additionalModules: [
        // i18n
        customTranslateModule,
        // 左侧
        customControlsModule,
        // 缩略图工具栏
        minimapModule,
        // 显示事务边界
        transactionBoundariesModule,
        lintModule,
        tokenSimulation
      ],
      moddleExtensions: {
        activiti: activitiModdleDescriptor
      },
      linting: {
        bpmnlint: bpmnlintConfig
      },
      keyboard: {
        bindTo: document.body
      }
    })
    // 去除LOGO
    const bjsIoLogo = document.querySelector('.bjs-powered-by')
    if (bjsIoLogo) {
      bjsIoLogo.remove();
    }
    document.querySelector('.djs-palette').style.display = 'inline-block'

    if (this.newProcessDiagramXml === '') {
      let xml = defaultDiagramXML
      let processKey = this.processInfo.processKey
      if (!this.processInfo.processKey.startsWith('p_')) {
        processKey = 'p_' + this.processInfo.processKey;
      }
      xml = xml.replace(/Process_1/g, processKey)
      xml = xml.replace(/Process_name_1/g, this.processInfo.processName)
      xml = xml.replace(/UserTask_Id/g, new Ids([32, 36, 1]).nextPrefixed('UserTask_'))
      xml = xml.replace(/SequenceFlow_Id/g, new Ids([32, 36, 1]).nextPrefixed('SequenceFlow_'))
      this.renderDiagram(xml)
    } else {
      this.renderDiagram(this.newProcessDiagramXml)
    }

    console.log('newProcessDiagramXml' + this.newProcessDiagramXml)

    this.renderDiagramLoading = false
  },
  methods: {
    // 保存bpmn模型数据
    saveBpmn(data) {
      this.$emit('saveBpmn', data)
      console.log('modeler接收了saveBpmn')
    },
    // 获取节点按钮
    getNodeAction(param, callback) {
      this.$emit('getNodeAction', param, val => { callback(val) })
      console.log('modeler接收了getNodeAction')
    },
    getAreaAction(callback) {
      // 获取区域动作
      this.$emit('getAreaAction', val => { callback(val) }) // 传函数给父组件
      console.log('modeler接收了getAreaAction')
    },
    getDepartmentAction(callback) {
      // 获取部门动作
      this.$emit('getDepartmentAction', val => { callback(val) }) // 传函数给父组件
      console.log('modeler接收了getDepartmentAction')
    },
    getRoleAction(callback) {
      // 获取角色动作
      this.$emit('getRoleAction', val => { callback(val) }) // 传函数给父组件
      console.log('modeler接收了getRoleAction')
    },
    getRuleAction(callback) {
      // 获取规则动作
      this.$emit('getRuleAction', val => { callback(val) }) // 传函数给父组件
      console.log('modeler接收了getRuleAction')
    },
    async renderDiagram(xml) {
      if (xml === '') {
        xml = defaultDiagramXML
        let processKey = this.processInfo.processKey
        if (!this.processInfo.processKey.startsWith('p_')) {
          processKey = 'p_' + this.processInfo.processKey;
        }
        xml = xml.replace(/Process_1/g, processKey)
        xml = xml.replace(/Process_name_1/g, this.processInfo.processName)
        xml = xml.replace(/UserTask_Id/g, new Ids([32, 36, 1]).nextPrefixed('UserTask_'))
        xml = xml.replace(/SequenceFlow_Id/g, new Ids([32, 36, 1]).nextPrefixed('SequenceFlow_'))
      }
      try {
        const result = await this.bpmnModeler.importXML(xml);
        const { warnings } = result;
        console.log(warnings);
        this.success();
      } catch (err) {
        console.log(err.message, err.warnings);
      }
    },
    success() {
      this.bpmnModeler.get('canvas').zoom('fit-viewport')
      // 设置 流程图预览速度
      this.bpmnModeler.get('animation').setAnimationSpeed(1.5)
      document.getElementsByClassName('toggle-mode')[0].innerHTML = '流程模拟 <span class="toggle"><i class="fa fa-toggle-off"></i></span>'
      const transactionBoundaries = this.bpmnModeler.get('transactionBoundaries');
      transactionBoundaries.show();
    },
    // 切换tab
    handleClick(tab, event) {
      this.showVarDict = false
      if (tab.name === 'first') {
        this.getProcessDiagramXML()
      } else if (tab.name === 'fourth') {
        this.getProcessDiagramXML()
      } else if (tab.name === 'third') {
        this.$nextTick(() => {
          this.showVarDict = true
        })
      } else if (tab.name === 'second') {
        this.getProcessDiagramXML()
      }
    },
    async getProcessDiagramXML() {
      if (this.bpmnModeler._customElements != null && this.bpmnModeler._customElements.length > 0) {
      // 将自定义的元素 加入到 _definitions
        this.bpmnModeler._definitions.rootElements[0].flowElements = this.bpmnModeler._definitions.rootElements[0].flowElements.concat(this.bpmnModeler._customElements[0])
      }
      try {
        const result = await this.bpmnModeler.saveXML({ format: true });
        this.processDiagramXml = result.xml.replace(/ns0:/g, 'activiti:')
      } catch (err) {
        this.$message.error(err);
      }
    }
  }
}
</script>

<style src="bpmn-js/dist/assets/diagram-js.css"></style>
<style src="bpmn-js/dist/assets/bpmn-font/css/bpmn.css"></style>
<style src="bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css"></style>
<style src="bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css"></style>
<style src="bpmn-js-bpmnlint/dist/assets/css/bpmn-js-bpmnlint.css"></style>
<style src="diagram-js-minimap/assets/diagram-js-minimap.css"></style>
<style src="bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css"></style>
<style>
* {
  box-sizing: border-box;
}

.processDesign {
  border: solid 1px #cccccc;
  width: 98%;
  min-width: 1080px;
  margin: 10px auto;
}
.centerClass{
  min-height: 600px;
  min-width: 600px;
  overflow-x: scroll;
}
.designHeader {
  /* height: 45px; */
  /* line-height: 45px; */
  margin: 0px auto;
  border-bottom: solid 1px #cccccc;
  /* border: solid 1px #666; */
}
.designFooter {
  height: 100px;
  /* border: solid 1px #666; */
}
.designRight{
  min-height: 600px;
  position: relative;
  /* border-top: solid 1px #cccccc; */
  /* border-bottom: solid 1px #cccccc; */
  /* border-left: solid 1px #cccccc; */
  margin-left: 10px;
}
.designLeft{
  position: relative;
  /* border: solid 1px #666; */
}
.bjsl-button {
  top: 20px;
  height: 30px;
}
 /* 缩略图 */
.djs-minimap {
  position: absolute;
  top: 20px;
  right: 10px;
  overflow: hidden;
  background-color: rgba(255, 255, 255, 0.9);
  border: solid 1px #ccc;
  border-radius: 2px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -webkit-user-select: none;
  cursor: pointer;
}
.djs-minimap .map {
    width: 250px;
    height: 150px;
}
.djs-minimap:not(.open) .toggle {
  width: 48px;
  height: 48px;
  line-height: 48px;
  text-align: center;
  background: url("./assets/diagram_images/minmap.svg") 0 0 no-repeat;
}
.djs-minimap.open .toggle:before {
  content: "关闭";
}
.djs-minimap:not(.open) .toggle:before {
  content: "";
}
.djs-container svg:nth-child(3){
  height: 100%;
  min-height: 850px;
  border: 1px solid  #cccccc;
  background: url('./assets/diagram_images/bg.svg') #fff;
}
a:link {
  text-decoration: none;
}
.content {
  position: relative;
  width: 100%;
  height: 100%;
}
.io-zoom-controls {
  width: auto;
  position: absolute;
  bottom: 15px;
  right: 15px;
  z-index: 100;
  overflow: hidden;
  background-color: rgba(255,255,255,0.9);
  border: solid 1px #ccc;
  border-radius: 2px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -webkit-user-select: none;
  cursor: pointer;
}
.io-zoom-reset {
  margin-bottom: 10px;
}
.io-control-list {
  list-style: none;
  padding: 5px;
  margin: 0;
}
.bjs-powered-by, .cjs-powered-by, .djs-powered-by, .io-control {
  background: #FFF;
  border-radius: 2px;
  border: solid 1px #E0E0E0;
  padding: 5px;
}
ul {
  padding-left: 30px;
}
ul {
  display: block;
  list-style-type: disc;
  margin-block-start: 1em;
  margin-block-end: 1em;
  margin-inline-start: 0px;
  margin-inline-end: 0px;
  padding-inline-start: 40px;
}
ul li button {
  cursor:pointer;
}
.io-editing-tools {
  width: auto;
  position: absolute;
  right: 5px;
  top: 5px;
  display: none;
  z-index: 100;
}
.fullscreenIcon  {
  cursor: pointer;
  background: url("./assets/diagram_images/fullscreen.svg") 0 0 no-repeat;;
}
.keyboardIcon {
  cursor: pointer;
  background: url("./assets/diagram_images/keyboard.svg")  0 0 no-repeat;;
}
.control button {
  padding: 0;
  outline: none;
  cursor: pointer;
  font-size: 22px;
  line-height: 26px;
  color: #555;
  background: none;
  border: none;
}

.content {
  position: relative;
  width: 100%;
  height: 100%;
}

.content > .message {
  width: 100%;
  height: 100%;
  text-align: center;
  display: table;
  font-size: 16px;
  color: #111;
}

.content > .message .note {
  vertical-align: middle;
  text-align: center;
  display: table-cell;
}

.content > .message.error .details {
  max-width: 500px;
  font-size: 12px;
  margin: 20px auto;
  text-align: left;
  color: #BD2828;
}

.content > .message.error pre {
  border: solid 1px #BD2828;
  background: #fefafa;
  padding: 10px;
  color: #BD2828;
}

.content:not(.with-error) .error, .content.with-error .intro, .content.with-diagram .intro {
  display: none;
}

.content .canvas {
  position: relative;
  float: left;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  min-height: 850px;
  border: 1px solid red;
}

.content .properties-panel-parent {
  display: none;
}

.content.with-diagram .canvas,
.content.with-diagram .properties-panel-parent {
  display: block;
}

</style>
